/*
 * Test.java
 *
 * Created on __DATE__, __TIME__
 */

package applet.molecule;

import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GraphicsConfiguration;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.View;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;

import com.sun.j3d.utils.universe.SimpleUniverse;

/**
 * 
 */
@SuppressWarnings("serial")
public class MoleculeNet extends javax.swing.JApplet {
	
	/** request type string of file data */
	public static final String GROUP_REQUEST_TYPE = "group";
	public static final String NON_GROUP_REQUEST_TYPE = "nonGroup";
	
	public static boolean isGroup;
	
	private String select;

	/** 
	 * total groups of the molecule data related to the specific point on energy 
	 * height image
	 */
	private int totalCount;

	/** 
	 * the X coordinate of the point on the energy height image the mouse 
	 * latest clicked. 
	 */
	private int currX;

	/** 
	 * the Y coordinate of the point on the energy height image the mouse 
	 * latest clicked. 
	 */
	private int currY;
	
	private List<List<Atom>> dispList;
	
	private List<DspPanel> dspList;
	
	private List<Atom> nullAtomList;

	private GraphicsConfiguration config;

	private CanvasPanel canvasPanel;
	
	private SimpleUniverse us;
	
	private View view;
	
	private int currIndex;
	
	private boolean axisVisible;

	private JButton expButton;
	private JButton coorButton;
	
	private ButtonGroup buttonGroup;
	
	private JPanel centerPanel;
	private JPanel groupPanel;
	private JLabel coorLabel;
	private JScrollPane scrollPane;
	private JPanel upPanel;
	
	public MoleculeNet(){
		dispList = new ArrayList<List<Atom>>();
		
		totalCount = 0;
		
		axisVisible = false;
		
		nullAtomList = new ArrayList<Atom>();

		config = SimpleUniverse.getPreferredConfiguration();
	}

	/** Initializes the applet Test */
	public void init() {		
		isGroup = Boolean.parseBoolean(getParameter("isGroup"));
		select = getParameter("select");
		
		try {
			UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		
		initComponents();
		
		final int defaultCount = 10;
		dspList = new ArrayList<DspPanel>(defaultCount);
		for(int i = 0; i < defaultCount; i++){
			addDspPanel(i);
		}
		
		us = new SimpleUniverse(canvasPanel.getCanvas());
		
		showUniverse(nullAtomList, axisVisible);
		
		if (!isGroup) {
			display(Integer.parseInt(getParameter("x")), Integer
					.parseInt(getParameter("y")));
		}
	}

	private void initComponents() {		
		final int scrollPaneSideBorder = 2;
		final int groupPanelHeight = DspButton.SIZE + 30;
		final int scrollPaneTotalHeight = groupPanelHeight + 30;
		
		upPanel = new JPanel();
		coorLabel = new JLabel();
		centerPanel = new JPanel();
		scrollPane = new JScrollPane();
		groupPanel = new JPanel();

		coorLabel.setText("At (water, hexonal)");
		upPanel.add(coorLabel);

		getContentPane().add(upPanel, java.awt.BorderLayout.PAGE_START);

		getContentPane().add(centerPanel, java.awt.BorderLayout.CENTER);
		
		final int canvasPanelSize = getHeight() - scrollPaneTotalHeight
				- scrollPaneSideBorder - 10;

		canvasPanel = new CanvasPanel(config, canvasPanelSize, isGroup);
		canvasPanel.setSize(new Dimension(canvasPanelSize, canvasPanelSize));

		centerPanel.setLayout(null);
		centerPanel.add(canvasPanel);
		
		final int additional = 8;
		canvasPanel.setLocation(getWidth() / 2 - canvasPanelSize / 2
				- additional, scrollPaneSideBorder);
		
		final int bWidth = 70;
		final int bHeight = 23;
		
		coorButton = new JButton("Axis");
		coorButton.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent evt) {
				axisVisible = !axisVisible;
				showUniverse(dspList.get(currIndex).getButton().getList(), axisVisible);
			}

		});

		coorButton.setSize(new Dimension(bWidth, bHeight));
		centerPanel.add(coorButton);
		coorButton.setLocation((int) canvasPanel.getLocation().getX()
				+ canvasPanelSize + additional / 2, canvasPanelSize
				- bHeight);
		
		coorButton.setEnabled(false);

		if (isGroup) {
			expButton = new JButton("Expand");
			expButton.addActionListener(new ActionListener() {

				public void actionPerformed(ActionEvent evt) {
					try {
						URL url = new URL(getCodeBase(), "nonGroup.jsp?x="
								+ currX + "&y=" + currY
								+ "&select=" + select
								+ "&index=" + currIndex);
						
						getAppletContext().showDocument(url, "_blank");
					} catch (MalformedURLException e) {
						e.printStackTrace();
					}
				}

			});

			expButton.setSize(new Dimension(bWidth, bHeight));
			centerPanel.add(expButton);
			expButton.setLocation((int) canvasPanel.getLocation().getX()
					+ canvasPanelSize + additional / 2, canvasPanelSize
					- bHeight*2 - 4);
			
			expButton.setEnabled(false);
		}

		groupPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
		scrollPane.setViewportView(groupPanel);
		scrollPane.setSize(getWidth() - scrollPaneSideBorder*2, groupPanelHeight);

		centerPanel.add(scrollPane);
		scrollPane.setLocation(scrollPaneSideBorder, getHeight() - scrollPaneTotalHeight);
		
		buttonGroup = new ButtonGroup();
	}
	
	private void showUniverse(List<Atom> list, boolean axisVisible){
		Attribute attrib = new Attribute();
		attrib.initParams(list);
		attrib.setAxisVisible(axisVisible);

		us.cleanup();
		us = new SimpleUniverse(canvasPanel.getCanvas());
		
		view = us.getViewer().getView();
		view.setBackClipDistance(attrib.GetBCDis());
		view.setFrontClipDistance(attrib.GetFCDis());

		us.getViewingPlatform().setNominalViewingTransform();
		BranchGroup scene = J3DRender.createSceneGraph(attrib);
		us.addBranchGraph(scene);

		if (list.size() > 0) {
			if(isGroup){
				expButton.setEnabled(true);
			}
			
			coorButton.setEnabled(true);
		} else {
			if (isGroup) {
				expButton.setEnabled(false);
			}
			
			coorButton.setEnabled(false);
		}
	}

	/**
	 * create a new molecule net applet associated with the point user latestly 
	 * clicked on the energy height image.
	 * 
	 * @param x the X coordinate of the point on the energy height image 
	 * 			the mouse latest clicked 
	 * @param y the Y coordinate of the point on the energy height image 
	 * 			the mouse latest clicked 
	 */
	public void display(int x, int y) {
		if (x > 40 || y > 40 || x < 0 || y < 0) {
			System.out.println("The point you click is invalid");
			return;
		}
		currX = x;
		currY = y;
		
		coorLabel.setText("At (" + currX + ", " + currY + ")");
		
		for(int i = 0; i<totalCount; i++){
			DspPanel p = dspList.get(i);

			p.getButton().setSelected(false);
			p.setVisible(false);
		}
		
		groupPanel.validate();
		scrollPane.validate();
		
		requestData(currX, currY);

		listButton();

		axisVisible = false;
		showUniverse(nullAtomList, axisVisible);
	}

	private void listButton() {		
		if(dspList.size() < totalCount){
			for(int i = dspList.size(); i<totalCount; i++){
				addDspPanel(i);
			}
		}
		
		for(int i = 0; i<totalCount; i++){
			DspPanel p = dspList.get(i);
			
			p.getButton().setAtomList(dispList.get(i));
			p.getButton().addActionListener(new ActionListener(){

				public void actionPerformed(ActionEvent evt) {
					DspButton b = (DspButton)evt.getSource();
					
					currIndex = b.getIndex();
					showUniverse(b.getList(), axisVisible);
				}
				
			});

			p.setVisible(true);
		}

		groupPanel.validate();
		scrollPane.validate();
	}
	
	private void addDspPanel(int index){
		DspPanel p = new DspPanel(isGroup, index);
		p.setPreferredSize(new Dimension(DspPanel.SIZE, DspPanel.SIZE));
		
		buttonGroup.add(p.getButton());
		dspList.add(p);
		groupPanel.add(p);
		p.setVisible(false);
	}

	/**
	 * Request the group <code>group</code> molecule net data from codeBase.
	 * <p/>
	 * 
	 * The transforming sequence is like this: <p/> |- total group number <br/>
	 * |-- the number of atoms of the 1st group <br/> |--- element x(3D
	 * coordinate) y z <br/> |--- element x y z <br/> |--- ... ... <br/> |---
	 * element x y z <br/> |-- the number of atoms of the 2nd group <br/> |---
	 * element x y z <br/> |--- ... ... <br/> |--- element x y z <br/> |-- the
	 * number of atoms of the 3rd group <br/> |--- element x y z <br/> |--- ...
	 * ... <br/> |--- element x y z <br/> |-- ... ... <br/> |-- the number of
	 * atoms of the last group <br/> |--- ... ... <br/> |- "end" string
	 * 
	 * @param x2D
	 *            the X coordinate of the point on the energy height image the
	 *            mouse latest clicked.
	 * @param y2D
	 *            the Y coordinate of the point on the energy height image the
	 *            mouse latest clicked.
	 */
	public void requestData(int x2D, int y2D) {
		try {
			URL url = null;
			if(Boolean.parseBoolean(getParameter("isGroup"))){
				url = new URL(getCodeBase(), "getData?type="
						+ GROUP_REQUEST_TYPE + "&select=" + select
						+ "&x=" + x2D + "&y=" + y2D);
			} else {
				url = new URL(getCodeBase(), "getData?type="
						+ NON_GROUP_REQUEST_TYPE + "&select=" + select + "&x="
						+ x2D + "&y=" + y2D + "&index=" + getParameter("index"));
			}

			HttpURLConnection conn = (HttpURLConnection) url.openConnection();
			conn.setDoInput(true);

			BufferedReader reader = new BufferedReader(new InputStreamReader(
					conn.getInputStream()));

			totalCount = Integer.parseInt(reader.readLine());

			String element;
			float x3D, y3D, z3D;
			String line;
			String[] split;
			int count;
			List<Atom> list = null;
			dispList.clear();
			while(true) {
				line = reader.readLine();
				if (line.equals("end")) {
					break;
				}

				list = new ArrayList<Atom>();
				count = Integer.parseInt(line);
				for (int i = 0; i < count; i++) {
					line = reader.readLine();
					split = line.split("[\\s]+");

					element = split[0];
					x3D = Float.parseFloat(split[1]);
					y3D = Float.parseFloat(split[2]);
					z3D = Float.parseFloat(split[3]);

					list.add(new Atom(element, x3D, y3D, z3D));
				}
				
				Collections.sort(list, new AtomComparator());
				
				dispList.add(list);
			}

			reader.close();
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

class AtomComparator implements Comparator<Atom> {

	public int compare(Atom a1, Atom a2) {
		if (a1.z < a2.z) {
			return -1;
		} else if (a1.z == a2.z) {
			return 0;
		} else {
			return 1;
		}
	}

}

